const express = require("express");
const fs = require("fs");
const { join, resolve } = require("path");
const multiparty = require("multiparty");
const cors = require("cors");

const PORT = 8888;
const uploadDir = `${__dirname}/upload`;
const app = express();
app.use(express.static("./"));
app.use(cors());

app.listen(PORT, () => console.log(`服务端已启动，端口号：${PORT}`));
app.use(express.urlencoded({ extended: false, limit: "2048mb" }));

// 判断upload文件夹的存在
function isDirSync(currentPath) {
  try {
    return fs.statSync(currentPath).isDirectory();
  } catch (e) {
    if (e.code === 'ENOENT') return false;
    throw e;
  }
}
function handleMultiparty(req, res, temp) {
  return new Promise((resolve, reject) => {
    const options = { maxFieldsSize: 200 * 1024 * 1024 };// multiparty的配置
    !temp ? (options.uploadDir = uploadDir) : null;
    const form = new multiparty.Form(options);
    form.parse(req, (err, fields, files) => {// multiparty解析
      if (err) return reject(err);
      resolve({ fields, files });
    });
  });
}

//查找已经上传的文件
function findSync(startPath) {
  const result = [];

  function finder(_path) {
    const files = fs.readdirSync(_path);
    files.forEach(item => {
      const _findPath = join(_path, item);
      const stats = fs.statSync(_findPath);
      if (stats.isFile()) result.push(item.split(".")[0]);
    });
  }

  finder(startPath);
  return result;
}

//查找上传过程中的文件
function findLoadingSync(startPath, hash) {
  const result = [];

  function finder(_path, isChild) {
    if (!isDirSync(join(__dirname, 'upload'))) {
      fs.mkdirSync(join(__dirname, 'upload'));
    }
    const _files = fs.readdirSync(_path);
    _files.forEach(item => {
      const _findPath = join(_path, item);
      const stats = fs.statSync(_findPath);
      if (stats.isDirectory() && hash == item) finder(_findPath, item);
      if (stats.isFile() && isChild == hash) result.push(item);
    });
  }

  finder(startPath);
  return result;
}

//判断当前文件是否曾经上传，如果上传且没有上传完成返回已经上传的文件切片名称
app.get("/loadingUpload", (req, res) => {
  const { hash } = req.query;
  const _hasUpList = findLoadingSync(uploadDir, hash);
  res.send({ code: 0, data: _hasUpList });
});

app.post("/upload", async (req, res) => {
  const { fields, files } = await handleMultiparty(req, res, true);

  const [chunk] = files.chunk;
  const [filename] = fields.filename;
  const _hash = /([0-9a-zA-Z]+)_\d+/.exec(filename)[1];
  let _path = `${uploadDir}/${_hash}`;
  const _hasUpList = findSync(uploadDir);
  if (_hasUpList.indexOf(_hash) > -1) {
    return res.send({ code: 2, msg: "当前文件已经上传！" });
  }
  !fs.existsSync(_path) ? fs.mkdirSync(_path) : null;
  _path = `${_path}/${filename}`;
  fs.access(_path, async (err) => { // 存在的则不再进行任何的处理
  if (!err) {
    return res.send({ code: 0, path: _path.replace(__dirname, `http://127.0.0.1:${PORT}`) });
  };

    // 不存在的再创建
    const readStream = fs.createReadStream(chunk.path);
    const writeStream = fs.createWriteStream(_path);
    readStream.pipe(writeStream);
    readStream.on("end", () => {
      fs.unlinkSync(chunk.path);
      res.send({ code: 0, path: _path.replace(__dirname, `http://127.0.0.1:${PORT}`) });
    });
  });
});

app.get("/merge", (req, res) => {
  const { hash } = req.query;
  const _path = `${uploadDir}/${hash}`;
  const fileList = fs.readdirSync(_path);
  let suffix;

  fileList.sort((a, b) => /_(\d+)/.exec(a)[1] - /_(\d+)/.exec(b)[1]);
  fileList.forEach(item => {
    !suffix ? (suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1]) : null;
    fs.appendFileSync( `${uploadDir}/${hash}.${suffix}`, fs.readFileSync(`${_path}/${item}`) );
    fs.unlinkSync(`${_path}/${item}`);
  });
  fs.rmdirSync(_path);
  res.send({ code: 0, path: `http://127.0.0.1:${PORT}/upload/${hash}.${suffix}` });
});

app.use((req, res) => {
  res.status(404);
  res.send("NOT FOUND!");
});
